/**
 * OrderServiceImpl.java
 * 
 * Copyright@2015 OVT Inc. All rights reserved. 
 * 
 * Dec 29, 2015
 */
package com.ovt.doorbell.payment.service;

import java.text.MessageFormat;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import com.ovt.doorbell.payment.common.utils.DateTimeUtils;
import com.ovt.doorbell.payment.dao.constant.MemberResourceStatus;
import com.ovt.doorbell.payment.dao.constant.PurchaseType;
import com.ovt.doorbell.payment.dao.constant.ResourceType;
import com.ovt.doorbell.payment.dao.vo.MemberProfile;
import com.ovt.doorbell.payment.dao.vo.MemberResource;
import com.ovt.doorbell.payment.dao.vo.Order;
import com.ovt.doorbell.payment.dao.vo.OrderRequest;
import com.ovt.doorbell.payment.dao.vo.Resource;
import com.ovt.doorbell.payment.service.constant.DoorbellConstants;
import com.ovt.doorbell.payment.service.exception.ServiceException;
import com.ovt.order.util.OVPayment;
import com.ovt.order.util.entity.OrderItem;

/**
 * OrderServiceImpl
 * 
 * @Author zhi.liu
 * @Version 1.0
 * @See
 * @Since [OVT Cloud Platform]/[API] 1.0
 */
public class OrderServiceImpl implements OrderService
{
    @Autowired
    private MemberProfileService memberProfileService;

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private PriceService priceService;

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.OrderService#createOrder(com.ovt.doorbell
     * .payment.dao.vo.OrderRequest)
     */
    @Override
    public Order createOrder(OrderRequest orderRequest) throws ServiceException
    {
        Order order = new Order(orderRequest);

        // 1. get member profile
        MemberProfile memberProfile = memberProfileService
                .getMemberProfile(orderRequest.getUserId());

        // 2. calculate fee
        priceService.calculateOrderFee(memberProfile, order);

        // 3. create payment order via Order-SDK
        com.ovt.order.util.entity.Order paymentOrder = convert2PaymentOrder(
                memberProfile, order, orderRequest);
        OVPayment.createOrder(paymentOrder);

        order.setOrderNo(paymentOrder.getOrderNo());

        return order;
    }

    private void updateOrderRemark(MemberProfile memberProfile,
            com.ovt.order.util.entity.Order order, OrderRequest orderRequest)
            throws ServiceException
    {
        String orderRemark = "";
        PurchaseType purchaseType = this.memberProfileService
                .getPurchaseType(memberProfile);

        if (purchaseType == PurchaseType.PURCHASE)
        {
            orderRemark = "New purchase";
        }
        else if (purchaseType == PurchaseType.UPGRADE)
        {
            orderRemark = "Upgrade ";

            // space upgrade?
            int fromNum = memberProfile.getResourceSize(ResourceType.SPACE);
            int toNum = orderRequest.getSpace();
            if (toNum > fromNum)
            {
                orderRemark += MessageFormat.format(
                        "space from [{0}]G to [{1}]G;", fromNum, toNum);
            }

            // flow upgrade?
            fromNum = memberProfile.getResourceSize(ResourceType.FLOW);
            toNum = orderRequest.getFlow();
            if (toNum > fromNum)
            {
                orderRemark += MessageFormat.format(
                        "flow from [{0}]G to [{1}]G;", fromNum, toNum);
            }
        }

        order.setRemark(orderRemark);
    }

    private com.ovt.order.util.entity.Order convert2PaymentOrder(
            MemberProfile memberProfile, Order doorbellOrder,
            OrderRequest orderRequest) throws ServiceException
    {
        com.ovt.order.util.entity.Order order = new com.ovt.order.util.entity.Order();

        order.setUserId(doorbellOrder.getUserId());
        order.setTotalFee(doorbellOrder.getTotalFee());

        OrderItem space = new OrderItem();
        Resource spaceResource = resourceService.getResource(
                ResourceType.SPACE, doorbellOrder.getSpace());
        space.setProductNo(spaceResource.getCode());
        space.setProductName(spaceResource.getName());
        space.setProductPrice(spaceResource.getPrice());
        space.setProductNum(doorbellOrder.getMonth());
        order.getOrderItemList().add(space);

        OrderItem flow = new OrderItem();
        Resource flowResource = resourceService.getResource(ResourceType.FLOW,
                doorbellOrder.getSpace());
        flow.setProductNo(flowResource.getCode());
        flow.setProductName(flowResource.getName());
        flow.setProductPrice(flowResource.getPrice());
        flow.setProductNum(doorbellOrder.getMonth());
        order.getOrderItemList().add(flow);

        this.updateOrderRemark(memberProfile, order, orderRequest);

        return order;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.OrderService#onPaidSuccess(java.lang
     * .String)
     */
    @Override
    public void onPaidSuccess(String userId, String orderNo)
            throws ServiceException
    {
        // 1. get member profile
        MemberProfile memberProfile = memberProfileService
                .getMemberProfile(userId);

        // 2. get order
        com.ovt.order.util.entity.Order order = OVPayment.getOrderDetail(
                userId, orderNo);

        // 3. purchase type is purchase or upgrade?
        PurchaseType purchaseType = memberProfileService
                .getPurchaseType(memberProfile);

        if (purchaseType == PurchaseType.PURCHASE)
        {
            this.processPurchase(memberProfile, order);
        }
        else if (purchaseType == PurchaseType.RENEW)
        {
            this.processRenew(memberProfile, order);
        }
        else
        {
            this.processUpgrade(memberProfile, order);
        }

    }

    private void processRenew(MemberProfile memberProfile,
            com.ovt.order.util.entity.Order order) throws ServiceException
    {
        List<OrderItem> items = order.getOrderItemList();
        for (OrderItem orderItem : items)
        {
            Resource resource = resourceService.getResource(orderItem
                    .getProductNo());

            MemberResource newResource = new MemberResource(resource.getType());
            newResource.setResourceSize(resource.getSize());
            newResource.setOrderNo(order.getOrderNo());
            newResource.setStatus(MemberResourceStatus.INACTIVE);

            // find old memberResource (same type)
            for (MemberResource mResource : memberProfile.getResources())
            {
                if (resource.getType() == mResource.getResourceType())
                {
                    newResource.setStartTime(mResource.getExpireTime());
                    newResource.setExpireTime(DateTimeUtils
                            .toTimestamp(DateTimeUtils.addDays(
                                    newResource.getStartTime(),
                                    DoorbellConstants.DAYS_OF_MONTH)));
                }
            }
        }

        memberProfileService.saveProfile(memberProfile, PurchaseType.RENEW);
    }

    private void processUpgrade(MemberProfile memberProfile,
            com.ovt.order.util.entity.Order order) throws ServiceException
    {
        List<OrderItem> items = order.getOrderItemList();
        for (OrderItem orderItem : items)
        {
            Resource resource = resourceService.getResource(orderItem
                    .getProductNo());

            MemberResource newResource = new MemberResource(resource.getType());
            newResource.setResourceSize(resource.getSize());
            newResource.setOrderNo(order.getOrderNo());
            newResource.setStatus(MemberResourceStatus.ACTIVE);
            newResource.setStartTime(DateTimeUtils.getCurrentTimestamp());

            // find old memberResource (same type)
            MemberResource oldResource = null;
            for (MemberResource mResource : memberProfile.getResources())
            {
                if (resource.getType() == mResource.getResourceType())
                {
                    oldResource = mResource;
                    break;
                }
            }

            if (oldResource != null)
            {
                if (resourceService.isDefaultResource(
                        oldResource.getResourceType(),
                        oldResource.getResourceSize()))
                {
                    memberProfile.removeResource(oldResource);
                }
                else
                {
                    oldResource.setStatus(MemberResourceStatus.CANCELLED);
                    oldResource.setEndTime(DateTimeUtils.getCurrentTimestamp());
                }
                
                newResource.setExpireTime(oldResource.getExpireTime());
                memberProfile.getResources().add(newResource);
            }
            
        }

        memberProfileService.saveProfile(memberProfile, PurchaseType.UPGRADE);
    }

    /**
     * New purchase, means old resources are default.
     * 
     * @param memberProfile
     * @param order
     * @throws ServiceException 
     */
    private void processPurchase(MemberProfile oldMemberProfile,
            com.ovt.order.util.entity.Order order) throws ServiceException
    {
        List<OrderItem> items = order.getOrderItemList();
        for (OrderItem orderItem : items)
        {
            Resource resource = resourceService.getResource(orderItem
                    .getProductNo());

            MemberResource memberResource = new MemberResource(
                    resource.getType());
            memberResource.setResourceSize(resource.getSize());
            memberResource.setOrderNo(order.getOrderNo());
            memberResource.setStatus(MemberResourceStatus.ACTIVE);
            memberResource.setStartTime(DateTimeUtils.getCurrentTimestamp());
            memberResource.setExpireTime(DateTimeUtils
                    .toTimestamp(DateTimeUtils.addDays(
                            memberResource.getStartTime(),
                            (int) orderItem.getProductNum()
                                    * DoorbellConstants.DAYS_OF_MONTH)));

            oldMemberProfile
                    .replaceResource(resource.getType(), memberResource);
        }

        memberProfileService.saveProfile(oldMemberProfile, PurchaseType.PURCHASE);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.ovt.doorbell.payment.service.OrderService#onRefundSuccess(java.lang
     * .String)
     */
    @Override
    public void onRefundSuccess(String userId)
    {
        // TODO Auto-generated method stub

    }
}
